package me.twoday.library.mine.common.image;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Bitmap.CompressFormat;
import android.os.Environment;
import android.text.format.DateUtils;
import android.util.Log;


/**
 * 이미지를 파일로 캐싱 처리 하는 클래스
 * 
 * @author 박우람
 * @since 2011.07.15
 */
public class ImageFileCache
{
	private static final String TAG = "ImageFileCache";
	private static final String CACHE_DIR_PATH = Environment.getExternalStorageDirectory().getAbsolutePath() + "/SoptLab/Cache";
	private static final String NOMEDIA_FILENAME = ".nomedia";
	private static final long CACHE_FILE_EXPIRATION = DateUtils.DAY_IN_MILLIS * 15;
	
	/**
	 * 기본적으로 캐시를 저장할 디렉토리를 생성하고 갤러리에 등록되지 않도록 .nomedia파일을 추가한다.
	 */
	private static void initExternalStorageDir()
	{
		File extMediaDir = new File(CACHE_DIR_PATH);
		File nomedia = new File(extMediaDir, NOMEDIA_FILENAME);
		
		if(!extMediaDir.exists())
		{
			extMediaDir.mkdirs();
		}
		
		if(!nomedia.exists())
		{
			try
			{
				nomedia.createNewFile();
			}
			catch(IOException e)
			{
				Log.e(TAG, e.getMessage());
				return;
			}
		}
	}
	
	/**
	 * URL형 주소에서 파일명만을 가져옵니다.
	 * 
	 * @param url 이미지의 URL 주소
	 * @return 해싱된 파일 이름
	 */
	private static String getHashFileNameFromUrl(String url)
	{
		try
		{
			MessageDigest md = MessageDigest.getInstance("MD5");
			md.update(url.getBytes());
			
			byte byteData[] = md.digest();
			
			StringBuffer sb = new StringBuffer();
			for (int i = 0; i < byteData.length; i++)
			{
				sb.append(Integer.toString((byteData[i] & 0xff) + 0x100, 16).substring(1));
			}
			
			return sb.toString();
		}
		catch(NoSuchAlgorithmException e)
		{
			Log.e(TAG, e.getMessage());
		}
		
		return null;
	}
	
	/**
	 * 파일캐시에서 원하는 이미지를 가져옵니다.
	 * 
	 * @param key 키
	 * @return 이미지
	 */
	public static Bitmap getBitmapFromCache(String key)
	{
		File cacheFile = new File(CACHE_DIR_PATH, getHashFileNameFromUrl(key));
		
		if(cacheFile != null && cacheFile.exists())
		{
			try
			{
				final Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(cacheFile));
				return bitmap;
			}
			catch(Exception e)
			{
				Log.e(TAG, e.getMessage());
			}
		}
		return null;
	}

	/**
	 * 비트맵 이미지를 파일 형태로 저장합니다.
	 * 
	 * @param key 키
	 * @param value 이미지
	 */
	public static void putBitmapToCache(String key, Bitmap value)
	{
		if(value == null)
		{
			return;
		}
		
		try
		{
			initExternalStorageDir();
			File cacheFile = new File(CACHE_DIR_PATH, getHashFileNameFromUrl(key));
			FileOutputStream fos = new FileOutputStream(cacheFile);
			value.compress(CompressFormat.PNG, 100, fos);
			fos.flush();
			fos.close();
		}
		catch(FileNotFoundException e)
		{
			Log.e(TAG, e.getMessage());
		}
		catch(IOException e)
		{
			Log.e(TAG, e.getMessage());
		}
	}
	
	/**
	 * 오래된 캐시 파일을 정리합니다.
	 */
	public static void cleanCaches()
	{
		if(Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED))
		{
			File extMediaDir = new File(CACHE_DIR_PATH);
			
			if(extMediaDir != null)
			{
				File[] fileList = extMediaDir.listFiles();
				
				if(fileList != null && fileList.length > 0)
				{
					int fileCounter = 0;
					for(File file : fileList)
					{
						if(System.currentTimeMillis() - file.lastModified() >= CACHE_FILE_EXPIRATION)
						{
							file.delete();
							fileCounter++;
						}
					}
					
					if(fileCounter > 0)
					{
						Log.d(TAG, fileCounter + "개의 오래된 캐시 파일을 삭제합니다.");
					}
				}
			}
		}
	}
}
